#include "EagleLib.h"
#include "Log.h"
#include "KernelObserver.h"
#include "BluetoothObserver.h"
#include "AudioChannelObserver.h"
#include "SimulateVideoEncoder.h"
#include "MediaFocusControl.h"
#include "GnssControl.h"
#include "DeviceTime.h"
#include "MediaInfoObserver.h"
#include "UsbSwitcher.h"
#include <stdlib.h>
#include "AccessoryLib.h"
#include "AppleCarPlay_AppStub.h"
#include "CarplayInput.h"
#include "screenrecord.h"
#include "virtual_serial.h"
#include "tinycap.h"
#include "tinyplay.h"
#include "VersionInfo.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/system_properties.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <fcntl.h>

#define OEM_PATH "/dev/zj_usb_accessory"
#define ZJ_SET_STRING_READ_MODE            _IO('M', 77)
#define ZJ_SET_CONTROL_DELAY_MODE          _IO('M', 66)
unsigned int string_black_vid_pid[128] = {0x04244921};
int string_black_vid_pid_num = 1;

static unsigned int delay_black_vid_pid[128] = {0x04244921};
static int delay_black_vid_pid_num = 1;

static CarPlayAppStubDelegate	c2iDelegate;
static StubAirPlayModeState 		gAirPlayModeStateRaw;
static float SM6225outRatio = 1.0f;
static int	gVideoWidth		= 1920;
static int	gVideoHeight	= 720;
static int	gOriginalDisplayWidth	= 1920;//原车分辨率宽度
static int	gOriginalDisplayHeight	= 720; //原车分辨率高度
static int	gOriginalSafeWidth	= 1920;//原车安全区域分辨率宽度
static int	gOriginalSafeHeight	= 720; //原车安全区域分辨率高度
static int	gOriginalStartXPixels	= 0;//原车安全区域分辨率宽度
static int	gOriginalStartYPixels	= 0; //原车安全区域分辨率高度
static int	gMaxFPS         = 30;
static int	gTouchFingers   = 1;
#define PROPERTY_VALUE_MAX 92
static char board_socmodel[PROPERTY_VALUE_MAX] = { 0 };
static char board_platform[PROPERTY_VALUE_MAX] = { 0 };
static char role_delay[PROPERTY_VALUE_MAX] = { 0 };
static char board_serial[40] = { 0 };
static int sessionConnected = 0; //0是断开，1是连接
static int hidGadgetFunc = 0; //0是走libusb，1是走hid
static char g_usb_udc_path[1024] = { 0 };

//AlertAudioFormat Info
static int	gAltSampleRate		= 48000;
static int	gAltBits	        = 16;
static int	gAltChannels	    = 1;
//MediaAudioFormat Info
static int	gMediaSampleRate	= 48000;
static int	gMediaBits	        = 16;
static int	gMediaChannels	    = 2;
//TelephoneAudioFormat Info
static int	gPhoneSampleRate	= 16000;
static int	gPhoneBits	        = 16;
static int	gPhoneChannels	    = 1;
//SpeechAudioFormat Info
static int	gSpeechSampleRate	= 16000;
static int	gSpeechBits	        = 16;
static int	gSpeechChannels	    = 1;

//net_card info
static int net_card = 0;
static int wl_carplay = 0; //是否是连接无线CarPlay逆向
static int wifi_connected = 0;

static int simulate_video = 0; //是否模拟发264文件数据

static int soft_video_encoder = 0; //是否使用软编码

static int software_activated = 1; //产品是否已经激活

//缓存信息
static int resolutionCalibration = 0; //0 不需要做分辨率校准，1需要分辨率校准
static int foreground = 0; //0 是CarPlay处于后台，1是前台
static int gRightHandDrive = 0;
static int gNightMode = 0;
static int gOemIconVisible = 0;
static char * versionInfo = NULL;
static char * deviceId = NULL;
static char * usbSerialNumber = NULL;
static char * usbUUID = NULL;
static struct MediaInfo * mediaInfo = NULL;
static struct CallStateInfo * callStateInfo = NULL;

#define KEYCODE_MEDIA_PLAY    126
#define KEYCODE_MEDIA_PAUSE   127
#define KEYCODE_MEDIA_PLAY_PAUSE   85
#define KEYCODE_MEDIA_STOP   86
#define KEYCODE_MEDIA_NEXT   87
#define KEYCODE_MEDIA_PREVIOUS   88
#define KEYCODE_VOICE_ASSIST   231
#define KEYCODE_BACK            4
#define KEYCODE_CALL            5
#define KEYCODE_ENDCALL            6
#define KEYCODE_DPAD_UP            19
#define KEYCODE_DPAD_DOWN            20
#define KEYCODE_DPAD_LEFT            21
#define KEYCODE_DPAD_RIGHT           22
#define KEYCODE_DPAD_CENTER          23

#define APP_HFP_OUTGOING 2
#define APP_HFP_INCOMING 3
#define APP_HFP_HANG_UP 4
#define APP_HFP_CONNECTING 5

static void calculateSM6225WidthHeight(int width,int height,int * outWidth,int * outHeight,float * outRatio);
static void calculateCodecRecorderWidthHeight(int width,int height,int * outWidth,int * outHeight,float * outRatio);
void SharkCarPlayInit();
int check_usb_usb_gadget_UDC();

static int _OnRequestAccessoryRead(ipod_t handle,uint8 * data, uint16 len,int *length){
	if( wl_carplay == 1)
	{
		return readRfcomm(data, len,length);
	}
	return AccessoryLib::getInstance()->accessoryRead(data, len,length);
}

static int _OnRequestAccessoryWrite(ipod_t handle,uint8 * data, uint16 len,int *length){
	if( wl_carplay == 1)
	{
		return writeRfcomm(data, len,length);
	}
	return AccessoryLib::getInstance()->accessoryWrite(data, len,length);
}

static int _OnRequestAccessoryUsbVidPid(ipod_t handle,uint16 * vid, uint16 * pid,int *length){
	return AccessoryLib::getInstance()->accessoryUsbVidPid(vid, pid,length);
}

static int _OnRequestDisableBluetooth(ipod_t handle){
	disconnectRfcomm();
	return 0;
}

static char* start_with(char*data, char* str) {
	if ('\0' == *str)
		return NULL;
	char* pos = data;
	char* sub = str;
	while (*sub == *pos && *sub != '\0') {
		++sub;
		++pos;
	}
	if (*sub == '\0') {
		return pos;
	} else {
		return NULL;
	}
}

void _SimulateVideoEncoderCallBack(void* data,int len){
	CarPlayAppStubSendVideo(data, len);
}

/**
 * 请求screenrecord开始录屏
 *
 */
 int _OnRequestScreenRecordStart(ipod_t handle,int  width, int height,int fps){
	 LOGD( "%s:%d width = %d ,height = %d \n", __func__, __LINE__, width, height);
	 // IE1表示carplay在前台， IE0表示carplay在后台
	foreground = 1 ;
	if( resolutionCalibration == 1)
	{
		write_serial("ID\r\n");
	}
	write_serial("IE1\r\n");
	__system_property_set("zj.zsender.focus.video", "1");
//	requestStartLocationInformation(1);
//	startScreenRecord(width, height, fps);
	OnCarPlaySessionConnected();
	DeviceTimeOnCarPlaySessionConnected();
	__system_property_get("ro.soc.model", board_socmodel);
	__system_property_get("ro.board.platform", board_platform);
	float outRatio = 1.0f;
	if (strcasecmp(board_platform, "mt8163") == 0)
	{
		//patch 20240220 对于录屏大于1080p必需裁剪 1920*1080
		bool crop = false;
		if((width >= height) && (width * height) > (1920 * 1080))
		{
			crop = true;
		}
		else if((height > width) && (width * height) > (1920 * 1080))
		{
			crop = true;
		}
		if(crop)
		{
			int outWidth = width;
			int outHeight = height;
			calculateCodecRecorderWidthHeight(width, height, &outWidth, &outHeight, &outRatio);
			width = outWidth;
			height = outHeight;
		}
	}
	else if (strcasecmp(board_socmodel, "SM6225") == 0 && soft_video_encoder == 0)
	{
		if((width * height) > (1920 * 1080))
		{
			//需要裁剪
			int outWidth = width;
			int outHeight = height;
			calculateSM6225WidthHeight(gOriginalDisplayWidth, gOriginalDisplayHeight, &outWidth, &outHeight, &outRatio);
			if( outRatio != 1.0f )
			{
				width = outWidth;
				height = outHeight;
			}
		}

	}
	LOGD( "PrepareEncoder %s:%d width = %d ,height = %d outRatio = %d\n", __func__, __LINE__, width, height,outRatio);

	int androidStartXPixels = gOriginalStartXPixels;
	int androidStartYPixels = gOriginalStartYPixels;
	int androidSafeWidth = gOriginalSafeWidth;
	int androidSafeHeight = gOriginalSafeHeight;
	if(outRatio != 1.0f )
	{
		LOGD( "PrepareEncoder %s:%d width = %d ,height = %d outRatio = %d\n", __func__, __LINE__, width, height,outRatio);

		androidStartXPixels = (int)((float)gOriginalStartXPixels * (float)outRatio);
		androidStartYPixels = (int)((float)gOriginalStartYPixels * (float)outRatio);

		int tempSafeWidth = (int)((float)gOriginalSafeWidth * (float)outRatio);
		int moduloSafeWidth = tempSafeWidth % 16;
		androidSafeWidth = tempSafeWidth - moduloSafeWidth;

		int tempSafeHeight = (int)((float)gOriginalSafeHeight * (float)outRatio);
		int moduloSafeHeight = tempSafeHeight % 16;
		androidSafeHeight = tempSafeHeight - moduloSafeHeight;

		LOGD( "PrepareEncoder %s:%d androidSafeWidth = %d ,androidSafeHeight = %d outRatio = %d\n", __func__, __LINE__, androidSafeWidth, androidSafeHeight,outRatio);
	}
	//for the screen adaption >>>
	char startpixels[100];
	char viewareas[100];
	int n = 0, len =0 ;
	n = sprintf( &startpixels[ len ], "%d",androidStartXPixels );
	len += ( n );

	n = sprintf( &startpixels[ len ], "x" );
	len += ( n );

	n = sprintf( &startpixels[ len ], "%d", androidStartYPixels );
	len += ( n );

	//viewareas
	n = 0;
	len = 0;
	n = sprintf( &viewareas[ len ], "%d",androidSafeWidth );
	len += ( n );

	n = sprintf( &viewareas[ len ], "x" );
	len += ( n );

	n = sprintf( &viewareas[ len ], "%d", androidSafeHeight );
	len += ( n );
    __system_property_set("persist.zj.zsender.startpixels", startpixels);
    __system_property_set("persist.zj.zsender.viewareas", viewareas);

    LOGD("_OnRequestScreenRecordStart optimize startpixels = %s  \n", startpixels );
    LOGD("_OnRequestScreenRecordStart optimize viewarea = %s  \n", viewareas );

	char setStartX  [100];
	char setStartY [100];
	snprintf( setStartX, sizeof(setStartX), "%d", androidStartXPixels );
	snprintf( setStartY, sizeof(setStartY), "%d", androidStartYPixels );
	__system_property_set("persist.zj.zsender.startpixels.x", setStartX);
	__system_property_set("persist.zj.zsender.startpixels.y", setStartY);

	char setSafeWidth  [100];
	char setSafeHeight [100];
	snprintf( setSafeWidth, sizeof(setSafeWidth), "%d", androidSafeWidth );
	snprintf( setSafeHeight, sizeof(setSafeHeight), "%d", androidSafeHeight );
	__system_property_set("persist.zj.zsender.area.width", setSafeWidth);
	__system_property_set("persist.zj.zsender.area.height", setSafeHeight);

    //for the screen adaption <<<

	if( simulate_video == 0 )
	{
		startRecordScreen(width, height, fps);
	}else{
		start_video_encoder(_SimulateVideoEncoderCallBack);
	}

	return 0;
}

 /**
  * 请求screenrecord停止录屏
  *
  */
int _OnRequestScreenRecordStop(ipod_t handle){
	LOGD( "%s:%d\n", __func__, __LINE__);
	foreground = 0 ;
	write_serial("IE0\r\n");
	if( simulate_video == 0 )
	{
		stopRecordScreen();
	}else{
		stop_video_encoder();
	}

 	return 0;
 }

/**
 * 请求audiorecord开始录取
 *
 */
int _OnRequestAudioRecordStart(ipod_t handle,int type){
	LOGD( "%s:%d\n", __func__, __LINE__);
	if( type == AUDIO_CHANNEL_NAVIGATION )
	{
		tinycap_set_parameter(type, gAltSampleRate, gAltBits, gAltChannels);
	}
	else if( type == AUDIO_CHANNEL_MEDIA )
	{
		if( mediaInfo == NULL )
		{
			mediaInfo =(struct MediaInfo *) malloc(sizeof( struct MediaInfo ));
		}
		mediaInfo->action = 1;
		mediaInfo->playbackStatus = 1; //0= Stoped , 1=Playing , 2=Pause
		sendMediaLibraryInfo(mediaInfo);

		tinycap_set_parameter(type, gMediaSampleRate, gMediaBits, gMediaChannels);
	}
	else if( type == AUDIO_CHANNEL_SPEECH )
	{
		tinycap_set_parameter(type, gSpeechSampleRate, gSpeechBits, gSpeechChannels);
	}
	else if( type == AUDIO_CHANNEL_PHONE )
	{
		tinycap_set_parameter(type, gPhoneSampleRate, gPhoneBits, gPhoneChannels);
	}
	tinycap_start(type);
	return 0;
}

 /**
  * 请求audiorecord停止录取
  *
  */
int _OnRequestAudioRecordStop(ipod_t handle,int type){
	LOGD( "%s:%d\n", __func__, __LINE__);
	if( type == AUDIO_CHANNEL_MEDIA )
	{
		if( mediaInfo == NULL )
		{
			mediaInfo =(struct MediaInfo *) malloc(sizeof( struct MediaInfo ));
		}
//		mediaInfo->action = 1;
		mediaInfo->playbackStatus = 2; //0= Stoped , 1=Playing , 2=Pause
		sendMediaLibraryInfo(mediaInfo);
	}
	tinycap_stop(type);
 	return 0;
 }

/**
 * 请求microphone开始录取
 *
 */
int _OnRequestMicrophoneStart(ipod_t handle,int type){
	LOGD( "%s:%d\n", __func__, __LINE__);
	if( type == AUDIO_CHANNEL_SPEECH )
	{
		tinyplay_set_parameter(type, gSpeechSampleRate, gSpeechBits, gSpeechChannels);
	}
	else if( type == AUDIO_CHANNEL_PHONE )
	{
		tinyplay_set_parameter(type, gPhoneSampleRate, gPhoneBits, gPhoneChannels);
	}
	tinyplay_start(type);
	return 0;
}

 /**
  * 请求microphone停止录取
  *
  */
int _OnRequestMicrophoneStop(ipod_t handle,int type){
	LOGD( "%s:%d\n", __func__, __LINE__);
	tinyplay_stop(type);
 	return 0;
 }

 /**
  * 请求libusb停止的操作,0代表关闭
  *
  */
void _OnRequestLibusbOperate(ipod_t handle,int operate){
	LOGD( "%s:%d\n", __func__, __LINE__);
	AccessoryLib::getInstance()->accessoryLibUninit();

 }


/**
 * CarPlay触摸事件
 *
 */
static void _OnAirPlayScreenTouchEvent(ipod_t handle,int action,int x,int y){
//	LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD("_OnAirPlayScreenTouchEvent action = %d ,x = %d ,y = %d SM6225outRatio = %f  \n", action,x,y ,SM6225outRatio);
	x *= SM6225outRatio;
	y *= SM6225outRatio;
	LOGD("_OnAirPlayScreenTouchEvent transform action = %d ,x = %d ,y = %d SM6225outRatio = %f  \n", action,x,y ,SM6225outRatio);
	LOGD("_OnAirPlayScreenTouchEvent transform gVideoWidth = %d ,gVideoHeight = %d \n", gVideoWidth,gVideoHeight );
	reverse_carplay_touch(x,y,action,gVideoWidth,gVideoHeight);
}

/**
 * CarPlay多点触摸事件
 *
 */
static void _OnAirPlayScreenMultiTouchEvent(ipod_t handle,int action,int x,int y,int action1,int x1,int y1){
//	LOGD( "%s:%d\n", __func__, __LINE__);
//	LOGD("_OnAirPlayScreenMultiTouchEvent action = %d ,x = %d ,y = %d, action1 = %d , x1 = %d ,y1 = %d  \n", action,x,y,action1, x1,y1 );
//	LOGD("_OnAirPlayScreenMultiTouchEvent gVideoWidth = %d ,gVideoHeight = %d \n", gVideoWidth,gVideoHeight );
	reverse_carplay__multi_touch(x,y,action,x1,y1,action1,gVideoWidth,gVideoHeight);
}

/**
 * CarPlayKnob触摸事件
 *
 */
static void _OnAirPlayScreenKnobEvent(ipod_t handle,int button,int home,
		int back,int x,int y,int wheel){
	LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "_OnAirPlayScreenKnobEvent button = %d ,home = %d ,back = %d ,inX = %d , inY = %d , inWheel = %d \n",
			button,home,back,
			x,y,wheel
			);

#if 1

	if(x == 127)//right
	{
		LOGD("input keyevent DPAD_RIGHT");
		reverse_carplay_key(KEYCODE_DPAD_RIGHT);
	}
	if(x == 129)//left
	{
		LOGD("input keyevent DPAD_LEFT");
		reverse_carplay_key(KEYCODE_DPAD_LEFT);
	}

	if(y == 127)//down
	{
		LOGD("input keyevent DPAD_DOWN");
		reverse_carplay_key(KEYCODE_DPAD_DOWN);
	}
	if(y == 129)//up
	{
		LOGD("input keyevent DPAD_UP");
		reverse_carplay_key(KEYCODE_DPAD_UP);
	}


	if(wheel == 255)//left
	{
		LOGD("input keyevent 21 DPAD_LEFT");
		reverse_carplay_key(21);
	}

	if(wheel == 1)//right
	{
		LOGD("input keyevent 22 DPAD_RIGHT");
		reverse_carplay_key(22);
	}

	if(button == 1)//enter
	{
		LOGD("input keyevent 23 DPAD_CENTER");
		reverse_carplay_key(23);
	}

	if(home == 2)
	{
		LOGD("input keyevent 3 HOME");
		reverse_carplay_key(3);
	}

	if(back == 4)
	{
		LOGD("input keyevent 4 BACK");
		reverse_carplay_key(4);
	}
#endif

}

/**
 * CarPlayMediaButtons
 *
 */
static void _OnAirPlayScreenMediaButtonsEvent(ipod_t handle,int button,int action){

	LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "_OnAirPlayScreenMediaButtonsEvent button = %d ,action = %d  \n",
			button,action
			);

#if 1
	if(button == 4)
	{
		//KEYCODE_MEDIA_PLAY_PAUSE
		LOGD("input keyevent KEYCODE_MEDIA_PLAY_PAUSE \n");
		reverse_carplay_key(KEYCODE_MEDIA_PLAY_PAUSE);
	}

	if(button == 1)
	{
		LOGD("input keyevent KEYCODE_MEDIA_NEXT \n");
		reverse_carplay_key(KEYCODE_MEDIA_NEXT);
	}

	if(button == 2)
	{
		LOGD("input keyevent KEYCODE_MEDIA_PREVIOUS \n");
		reverse_carplay_key(KEYCODE_MEDIA_PREVIOUS);
	}
	if(button == 100)
	{
		reverse_carplay_key(KEYCODE_CALL);
		LOGD("input keyevent KEYCODE_TELEPHONE_ANSWER KEYCODE_CALL\n");
		write_serial("IG5\r\n");
	}
	if(button == 101)
	{
		reverse_carplay_key(KEYCODE_ENDCALL);
		LOGD("input keyevent KEYCODE_TELEPHONE_HANGUP KEYCODE_ENDCALL\n");
		write_serial("IG6\r\n");
	}

	if(button == 1400)
	{
		reverse_carplay_key(KEYCODE_BACK);
		LOGD("input keyevent KEYCODE_BACK\n");
	}

	if(button == KEYCODE_MEDIA_STOP)
	{
		reverse_carplay_key(KEYCODE_MEDIA_STOP);
	}

	if(button == KEYCODE_MEDIA_PLAY)
	{
		reverse_carplay_key(KEYCODE_MEDIA_PLAY);
	}

	if(button == KEYCODE_MEDIA_PAUSE)
	{
		reverse_carplay_key(KEYCODE_MEDIA_PAUSE);
	}

	if(button == 1500)
	{
		write_serial("IF\r\n");
		//6.IF  //表示原车方向盘按照语音按键，一般短按用原车的语音，长按2s用carplay语音
		LOGD("input keyevent KEYCODE_VOICE_ASSIST \n");
		reverse_carplay_key(KEYCODE_VOICE_ASSIST);
	}

#endif

}

static void calculateCodecRecorderWidthHeight(int width,int height,int * outWidth,int * outHeight,float * outRatio){
	int originalWidth = width;
	int originalHeight = height;
	float ratio = 1.0;
	if(width >= height)
	{
		//横屏
		float wRatio = (float)((float)1920 / (float)originalWidth);
		float hRatio = (float)((float)1080 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;

		LOGD("landscape calculateCodecRecorderWidthHeight width = %d  \n",width);
		LOGD("landscape calculateCodecRecorderWidthHeight height = %d  \n",height);
		LOGD("landscape calculateCodecRecorderWidthHeight ratio = %f  \n",ratio);
	}else {
		//竖屏
		float wRatio = (float)((float)1080 / (float)originalWidth);
		float hRatio = (float)((float)1920 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;

		LOGD("calculateCodecRecorderWidthHeight width = %d  \n",width);
		LOGD("calculateCodecRecorderWidthHeight height = %d  \n",height);
		LOGD("calculateCodecRecorderWidthHeight ratio = %f  \n",ratio);
	}
	*outWidth = width;
	*outHeight = height;
	*outRatio = ratio;
}

static void calculateMT8163WidthHeight(int width,int height,int * outWidth,int * outHeight,float * outRatio){
	int originalWidth = width;
	int originalHeight = height;
	float ratio = 1.0;
	if(width > height)
	{
		//横屏
		float wRatio = (float)((float)1366 / (float)originalWidth);
		float hRatio = (float)((float)768 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;
		LOGD("landscape calculateWidthHeight width = %d  \n",width);
		LOGD("landscape calculateWidthHeight height = %d  \n",height);
		LOGD("landscape calculateWidthHeight ratio = %f  \n",ratio);
	}else {
		//竖屏
		float wRatio = (float)((float)768 / (float)originalWidth);
		float hRatio = (float)((float)1366 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;

		LOGD("calculateWidthHeight width = %d  \n",width);
		LOGD("calculateWidthHeight height = %d  \n",height);
		LOGD("calculateWidthHeight ratio = %f  \n",ratio);
	}
	*outWidth = width;
	*outHeight = height;
	*outRatio = ratio;
}

static void calculateSM6225WidthHeight(int width,int height,int * outWidth,int * outHeight,float * outRatio){
	int originalWidth = width;
	int originalHeight = height;
	float ratio = 1.0;
	if(width >= height)
	{
		//横屏
		float wRatio = (float)((float)1920 / (float)originalWidth);
		float hRatio = (float)((float)1080 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;
		LOGD("landscape calculateWidthHeight width = %d  \n",width);
		LOGD("landscape calculateWidthHeight height = %d  \n",height);
		LOGD("landscape calculateWidthHeight ratio = %f  \n",ratio);
	}else {
		//竖屏
		float wRatio = (float)((float)1080 / (float)originalWidth);
		float hRatio = (float)((float)1920 / (float)originalHeight);
		ratio = wRatio < hRatio ? wRatio:hRatio;

		int tempHeight = height *ratio;
		int moduloHeight = tempHeight % 16;
		height = tempHeight - moduloHeight;

		int tempWidth =  originalWidth*ratio;
		int moduloWidth = tempWidth % 16;
		width = tempWidth - moduloWidth;
		LOGD("calculateWidthHeight width = %d  \n",width);
		LOGD("calculateWidthHeight height = %d  \n",height);
		LOGD("calculateWidthHeight ratio = %f  \n",ratio);
	}
	*outWidth = width;
	*outHeight = height;
	*outRatio = ratio;
}

/**
 * CarPlay Screen Display
 *
 */
static void _OnAirPlayScreenDisplay(ipod_t handle,int width,int height,int fps,int safeWidth,int safeHeight,int originXPixels,int originYPixels,int fingers){
	LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD("_OnAirPlayScreenDisplay width = %d ,height = %d ,fps = %d,safeWidth = %d ,safeHeight = %d ,,originXPixels = %d ,originYPixels = %d ,fingers = %d  \n", width,height,fps ,safeWidth,safeHeight,originXPixels,originYPixels,fingers);

	gOriginalDisplayWidth = width;
	gOriginalDisplayHeight = height;
	gOriginalSafeWidth = safeWidth;
	gOriginalSafeHeight = safeHeight;
	gOriginalStartXPixels = originXPixels;
	gOriginalStartYPixels = originYPixels;
	gTouchFingers = fingers;
	gMaxFPS = fps;
	//patch for 6225
	__system_property_get("ro.soc.model", board_socmodel);
	__system_property_get("ro.board.platform", board_platform);
	uint16 vid = 0x0000;
	uint16 pid = 0x0000;
	int length = 2;
	AccessoryLib::getInstance()->accessoryUsbVidPid(&vid, &pid,&length);

	//patch for 2024.06.26 >>>
	if (strcmp(board_socmodel, "SM6225") == 0 )
	{
		//vid:0x1234 pid:0xfff1
		if( vid == 0x1234 && pid == 0xfff1)
		{
			if((gOriginalDisplayWidth * gOriginalDisplayHeight) > (1920 * 1080))
			{
				__system_property_set("persist.sys.softsr", "1");
				soft_video_encoder = 1;
			}

		}
	}
	//patch for 2024.06.26 <<<

	//1.确定显示分辨率
	//2.设置显示分辨率
	if(safeWidth > 0 && safeHeight > 0)
	{
		width = safeWidth;
		height = safeHeight;
	}
	float outRatio = 1.0f;
	if (strcmp(board_platform, "mt8163") == 0)
	{
		//联发科MTK8163
		if((width * height) > (1366 * 768))
		{
			//需要裁剪
			int outWidth = width;
			int outHeight = height;
			calculateMT8163WidthHeight(width, height, &outWidth, &outHeight, &outRatio);
			if( outRatio != 1.0f )
			{
				width = outWidth;
				height = outHeight;
			}
		}

	}
	else if (strcmp(board_socmodel, "SM6225") == 0 && soft_video_encoder == 0)
	{
		LOGD("_OnAirPlayScreenDisplay optimize SM6225 871 \n");
		//高通680
		if((width * height) > (1920 * 1080))
		{
			//需要裁剪
			int outWidth = width;
			int outHeight = height;
			calculateSM6225WidthHeight(width, height, &outWidth, &outHeight, &outRatio);
			if( outRatio != 1.0f )
			{
				width = outWidth;
				height = outHeight;
			}
		}

	}
	if(width >= height )
	{
		//横屏
		__system_property_set("persist.panel.orientation", "0");
	}else{
		//竖屏
		__system_property_set("persist.panel.orientation", "90");
	}
	gVideoWidth  = width;
	gVideoHeight = height;
	if( outRatio != 1.0f )
	{
		SM6225outRatio = outRatio;
	}

	char	panelWidth  [ 100 ];
	char	panelHeight [ 100 ];

	char	panelmWidth  [ 100 ];
	char	panelmHeight [ 100 ];

	__system_property_get("persist.panel.width", panelWidth);
	__system_property_get("persist.panel.height", panelHeight);

	__system_property_get("persist.panel.mwidth", panelmWidth);
	__system_property_get("persist.panel.mheight", panelmWidth);

	LOGD( "Set android resolution width: %d\n",width);
	LOGD( "Set android resolution height: %d\n",height);

	if( strlen(panelWidth)>0 && strlen(panelHeight)>0 )
	{
		//判读两个值是否相等，不相等要重启适配分辨率
		int pWidth  = atoi(panelWidth);
		int pHeight = atoi(panelHeight);
		if(pWidth==width && pHeight==height)
		{
			LOGD( "Video resolution are same ! %s:%d\n", __func__, __LINE__);
			return;
		}
	}

	//直接需要重启适配分辨率
	char setWidth  [100];
	char setHeight [100];
	snprintf( setWidth, sizeof(setWidth), "%d", width );
	snprintf( setHeight, sizeof(setHeight), "%d", height );
	__system_property_set("persist.panel.width", setWidth);
	__system_property_set("persist.panel.height", setHeight);

	__system_property_set("persist.panel.mwidth", setWidth);
	__system_property_set("persist.panel.mheight", setHeight);

	LOGD( "Video resolution calibration reboot ! %s:%d\n", __func__, __LINE__);
//	4.ID  //表示连接上一个不同分辨率的车， 收到可以提示客户， 并重启机器
	resolutionCalibration = 1;
	__system_property_set("persist.sys.resolution.calibration", "1");

}


/**
 * CarPlay AudioFormat
 *
 */
static void _OnAirPlayAudioFormatInfo(ipod_t handle,int streamType,int sampleRate,int bits,int channels){
	LOGD( " %s:%d\n", __func__, __LINE__);
	LOGD( " %s, streamType = %d , sampleRate = %d, bits = %d, channels = %d \n", __func__,streamType,sampleRate,bits,channels);
	if( streamType == AUDIO_CHANNEL_NAVIGATION )
	{
		gAltSampleRate = sampleRate;
		gAltBits = bits;
		gAltChannels = channels;
	}
	else if( streamType == AUDIO_CHANNEL_MEDIA )
	{
		gMediaSampleRate = sampleRate;
		gMediaBits = bits;
		gMediaChannels = channels;
	}
	else if( streamType == AUDIO_CHANNEL_SPEECH )
	{
		gSpeechSampleRate = sampleRate;
		gSpeechBits = bits;
		gSpeechChannels = channels;
	}
	else if( streamType == AUDIO_CHANNEL_PHONE )
	{
		gPhoneSampleRate = sampleRate;
		gPhoneBits = bits;
		gPhoneChannels = channels;
	}

}

/**
 * CarPlay Modes Changed
 *
 */
static void _OnAirPlayModesChanged(ipod_t handle,int screen,int audio,int permAudio
		,int speechEntity,int speechMode,int phoneCall,int turnByTurn){
	LOGD( "%s:%d\n", __func__, __LINE__);

	gAirPlayModeStateRaw.screen = screen;
	gAirPlayModeStateRaw.mainAudio = audio;
	gAirPlayModeStateRaw.permMainAudio = permAudio;
	gAirPlayModeStateRaw.speech.entity = speechEntity;
	gAirPlayModeStateRaw.speech.mode = speechMode;
	gAirPlayModeStateRaw.phoneCall = phoneCall;
	gAirPlayModeStateRaw.turnByTurn = turnByTurn;

	if( gAirPlayModeStateRaw.mainAudio == 1)
	{
		//得到声音焦点
		write_serial("IJ\r\n");
	}else{
		//失去声音焦点
		write_serial("IC\r\n");
	}

}

/**
 * CarPlay AudioFocusChanged
 *
 */
static void _OnAirPlayAudioFocusChanged(ipod_t handle,int audioType,int ownFocus){
	LOGD( "%s:%d audioType = %d , ownFocus = %d \n", __func__, __LINE__,audioType, ownFocus);

	OnAirPlayAudioFocusChanged(audioType, ownFocus);

}

/**
 * CarPlay _OnAirPlayRequestNetworkCard
 *
 */
static void _OnAirPlayRequestNetworkCard(ipod_t handle,int open){
	LOGD( "%s:%d open = %d \n", __func__, __LINE__,open);
	LOGD( "ifconfig usb0 up ");
	system("ifconfig usb0 up");

}
/**
 * CarPlay SetNightMode Changed
 *
 */
static void _OnAirPlaySetNightMode(ipod_t handle,int nightMode){
	LOGD( "%s:%d\n", __func__, __LINE__);
	gNightMode = nightMode;

	char	darkTheme [ 20 ];
	__system_property_get("persist.applepie.auto.darktheme",darkTheme);
	if(strlen(darkTheme) == 0 || strcmp(darkTheme, "0") == 0)
	{
		if(nightMode == 1)
		{
			__system_property_set("sys.shark.night.mode", "1");
			write_serial("IN1\r\n");
		}else{
			__system_property_set("sys.shark.night.mode", "0");
			write_serial("IN0\r\n");
		}
	}

}

/**
 * CarPlay Info Changed
 *
 */
static void _OnAirPlayInfoChanged(ipod_t handle,int rightHandDrive,int oemIconVisible,int nightMode){
	LOGD( "%s:%d\n", __func__, __LINE__);

	gRightHandDrive = rightHandDrive;
	gOemIconVisible = oemIconVisible;
	gNightMode = nightMode;
	char charHanddrive  [10];
	snprintf( charHanddrive, sizeof(charHanddrive), "%d", gRightHandDrive );
	__system_property_set("sys.lynx.handdrive", charHanddrive);
	__system_property_set("persist.sys.lynx.handdrive", charHanddrive);

//	9.II  // II1 显示返回图标   II0 禁用返回图标
	if(oemIconVisible == 1)
	{
		write_serial("II1\r\n");
	}else{
		write_serial("II0\r\n");
	}
//	11.IM  // IM0 左   IM1 右
	if(rightHandDrive == 1)
	{
		write_serial("IM1\r\n");
	}else{
		write_serial("IM0\r\n");
	}
	if(gNightMode == 1)
	{
		write_serial("IN1\r\n");
	}else{
		write_serial("IN0\r\n");
	}


}

/**
 * CarPlay WifiConfigurationInformation Changed
 *
 */
static void _OnAirPlayWifiConfigurationInformation(ipod_t handle,const void * data){
	LOGD( "%s:%d\n", __func__, __LINE__);
	if( wl_carplay == 1 && wifi_connected == 0)
	{
		write_serial("IW\r\n");
		wifi_connected = 1;
	}
}

/**
 * CarPlay LocationInfo Changed
 *
 */
static void _OnAirPlayLocationInfoChanged(ipod_t handle,char * data){
	LOGD( "%s:%d\n", __func__, __LINE__);

	char	originalGPS [ 20 ];
	__system_property_get("persist.origin_car.gps",originalGPS);
	if(strlen(originalGPS) == 0 || strcmp(originalGPS, "0") == 0)
	{
		return;
	}

	__system_property_set("sys.gps.on", "1");
	LOGD( "%s:%d location = %s \n", __func__, __LINE__,data);

	int len = strlen(data) + 2;

	char gnss_data[len];
	snprintf( gnss_data, len, "%s\r\n", data );

	LOGD( "%s:%d gnss_data = %s \n", __func__, __LINE__,gnss_data);

	write_gnss_serial(gnss_data);

}

void _OnAudioChannelChanged(int channel ){
	//LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "%s:%d\n", __func__, channel);
	if(sessionConnected == 1)
	{
		//获取vid pid
		uint16 vid = 0x0000;
		uint16 pid = 0x0000;
		int length = 2;
		AccessoryLib::getInstance()->accessoryUsbVidPid(&vid, &pid,&length);
		if( vid == 0x8086 && pid == 0x9999)
		{
			if( channel == AUDIO_CHANNEL_SPEECH )
			{
				channel = AUDIO_CHANNEL_PHONE;
			}
		}
		OnRequestAudioChannelChanged(channel);
//		CarPlayAppStubSetAudioChannel(channel);

	}

}


void _OnMediaLibraryChanged(struct MediaMetadata * metadata ){
	LOGD( "%s:%d\n", __func__, __LINE__);
	if(sessionConnected == 1)
	{
		if( mediaInfo != NULL )
		{
			free( mediaInfo );
		}
		mediaInfo =(struct MediaInfo *) malloc(sizeof( struct MediaInfo ));
		memcpy(mediaInfo, metadata, sizeof( struct MediaInfo ));
		mediaInfo->playbackStatus = 1;
//		mediaInfo->action = 2;
		char	displayMediaInfo [ 20 ];
		__system_property_get("persist.sys.media.id3",displayMediaInfo);
		if(strlen(displayMediaInfo) > 0 && strcmp(displayMediaInfo, "1") == 0)
		{
			sendMediaLibraryInfo(mediaInfo);
		}
	}

}

void _OnGnssStartLocation(){

	requestStartLocationInformation(1);
}

void _OnSendDeviceTimeUpdate(){

	requestSendDeviceTimeUpdate( );
}

/**
 * CarPlay会话停止了
 *
 */
static void _OnAirPlaySessionStoped(ipod_t handle){
	LOGD( "%s:%d\n", __func__, __LINE__);
//	__system_property_set("sys.qcom.main.start", "0");
	__system_property_set("sys.suding.reverse.connect", "0");
	sessionConnected = 0;
	wifi_connected = 0;
	write_serial("IA\r\n");

	cancel_observe_audio_channel();
	cancel_observe_media_info();

	OnCarPlaySessionDisconnected();
	DeviceTimeOnCarPlaySessionDisconnected();

	_OnRequestScreenRecordStop( 0 );

#if 0
		char mdnsd[40];
		__system_property_get("sys.suding.mdnsd.pid",mdnsd);
		LOGD( "_OnAirPlaySessionStoped mdnsd pid --> %s  \n" , mdnsd);
		int mdnsd_pid =atoi(mdnsd);
		kill(mdnsd_pid, SIGINT);
#endif
}

int _OnAirPlayCarPlayAppStubRequestAudioFocus(int audioChannel)
{
	int callState = 0;
	if( audioChannel == AUDIO_CHANNEL_PHONE && callStateInfo != NULL )
	{
		uint16 vid = 0x0000;
		uint16 pid = 0x0000;
		int length = 2;
		AccessoryLib::getInstance()->accessoryUsbVidPid(&vid, &pid,&length);
		// vid:0x8087 pid:0x0a68 奇瑞EXCEED
		if( vid == 0x8087 && pid == 0x0a68)
		{
			//status = 2;//2 Ringing
			callState = callStateInfo->status;
		}
	}
	CarPlayAppStubRequestAudioFocus(audioChannel,callState);
	if( audioChannel == AUDIO_CHANNEL_MEDIA )
	{
		if( mediaInfo == NULL )
		{
			mediaInfo =(struct MediaInfo *) malloc(sizeof( struct MediaInfo ));
		}
		mediaInfo->playbackStatus = 1; //0= Stoped , 1=Playing , 2=Pause
		mediaInfo->action = 1;
//		sendMediaLibraryInfo(mediaInfo);
	}

	return 0;
}

int _OnAirPlayCarPlayAppStubAbandonAudioFocus(int audioChannel)
{
	CarPlayAppStubAbandonAudioFocus(audioChannel);
	if( audioChannel == AUDIO_CHANNEL_MEDIA )
	{
		if( mediaInfo == NULL )
		{
			mediaInfo =(struct MediaInfo *) malloc(sizeof( struct MediaInfo ));
		}
		mediaInfo->playbackStatus = 0;
//		mediaInfo->playbackStatus = 2; //0= Stoped , 1=Playing , 2=Pause
//		mediaInfo->action = 1;
//		sendMediaLibraryInfo(mediaInfo);
	}
	return 0;
}

/**
 * CarPlay会话开始了
 *
 */
static void _OnAirPlaySessionStarted(ipod_t handle){
	LOGD( "%s:%d\n", __func__, __LINE__);
	int touchRet=open_touch(gVideoWidth,gVideoHeight,gTouchFingers);
	if(touchRet<=0){
		LOGD("open touch event error");
	}else{
		LOGD("open touch event success");
	}
	__system_property_set("sys.qcom.main.start", "1");
	__system_property_set("sys.suding.reverse.connect", "1");
	sessionConnected = 1;
	write_serial("IB\r\n");
	if( software_activated )
	{
		start_observe_audio_channel(_OnAudioChannelChanged);
	}else{
		LOGE( "%s:%d Warning product not activated then sound slient.\n", __func__, __LINE__);
	}

	start_observe_media_info(_OnMediaLibraryChanged);

	RegisterRequestAudioFocus(_OnAirPlayCarPlayAppStubRequestAudioFocus);
	RegisterAbandonAudioFocus(_OnAirPlayCarPlayAppStubAbandonAudioFocus);
	RegisterRequestSetupAudio(CarPlayAppStubAudioStart);
	RegisterRequestTeardownAudio(CarPlayAppStubAudioStop);

	RegisterRequestStartLocation(_OnGnssStartLocation);
	RegisterSendDeviceTimeUpdate(_OnSendDeviceTimeUpdate);

//	char	originalGPS [ 20 ];
//	__system_property_get("persist.origin_car.gps",originalGPS);
//	if(strlen(originalGPS) > 0 && strcmp(originalGPS, "1") == 0)
//	{
//		requestStartLocationInformation(1);
//	}

}

void _ScreenRecordVideoCallBack(void* data,int len){
	CarPlayAppStubSendVideo(data, len);
}

void _AudioRecordPcmCallBack(void* data,int len,int frames){
	CarPlayAppStubSendAudio(data, len, frames);
}

void _MicrophoneRecordPcmCallBack(void* data,int len,int frames,uint64_t timestamp){
	CarPlayAppStubReadAudio(data, len, frames, timestamp);
}

void shark_at_command_process(const char* buffer,int size) {
	char * data = NULL;
	LOGD("AT_CMD = %s \n", buffer); //返回原车
    if (strcmp(buffer, "AT#CB\r\n") == 0) {
        // AT#CB back to original car
    	LOGD("AT#CB = back to original car \n");
        CarPlayAppStubBack2Home();
    }
    else if (strcmp(buffer, "AT#CA\r\n") == 0) {
    	//1.AT#CA  //表示查询当前状态
    	if(sessionConnected == 1)
    	{
    		//IB  //表示carplay连接
    		write_serial("IB\r\n");
    	}else{
    		//1.IA   //表示carplay断开
    		write_serial("IA\r\n");
    	}
    	if(resolutionCalibration == 1)
    	{
    		write_serial("ID\r\n");
    	}
    	if(foreground == 1)
    	{
    		write_serial("IE1\r\n");
    	}else{
    		write_serial("IE0\r\n");
    	}
    	if(gOemIconVisible == 1)
    	{
    		write_serial("II1\r\n");
    	}else{
    		write_serial("II0\r\n");
    	}

    	if(gRightHandDrive == 1)
    	{
    		write_serial("IM1\r\n");
    	}else{
    		write_serial("IM0\r\n");
    	}

		if( software_activated )
		{
			write_serial("IU1\r\n"); //产品已激活
		}else{
			write_serial("IU0\r\n");//产品未激活
		}

    	char	darkTheme [ 20 ];
    	__system_property_get("persist.applepie.auto.darktheme",darkTheme);
    	if(strlen(darkTheme) == 0 || strcmp(darkTheme, "0") == 0)
    	{
        	if(gNightMode == 1)
        	{
        		write_serial("IN1\r\n");
        	}else{
        		write_serial("IN0\r\n");
        	}

    	}
    }
    else if (strcmp(buffer, "AT#CD\r\n") == 0) {
    	//3.AT#CD  //查询版本号
    	char version [200];
    	snprintf( version, sizeof(version), "IH%s\r\n",versionInfo);
    	write_serial(version);
    }
    else if ((data = start_with((char *)buffer, "AT#CF")) != NULL) {
    	//3.AT#CF  //电话状态
    	//34G Phone15977938326
    	LOGD( "CallState serial receive data = %s  \n",data);
    	int separatorIndex = 0;
    	for(int i=0; i < size; i++ )
    	{
//    		LOGD( "CallState data = %02X  \n",data[i]);
    		if(data[i] == 0xFF)
    		{
    			separatorIndex = i;
    			break;
    		}
    	}
    	char startZone [separatorIndex + 1 ];
    	char endZone [size - separatorIndex - 1];

    	memset(startZone,0,(separatorIndex + 1));
    	startZone [separatorIndex] ='\0';
    	memcpy(startZone,data,separatorIndex);

    	memset(endZone,0,(size - separatorIndex - 1));
    	memcpy(endZone,data+(separatorIndex+1),(size - separatorIndex - 1));

    	LOGD( "CallState serial receive data startZone = %s  \n",startZone);
    	LOGD( "CallState serial receive data endZone = %s  \n",endZone);


    	int len = sizeof( startZone );
    	char state[2] = { 0 };
    	memset(state,0,2);
    	memcpy(state,startZone,1);
    	state [1] ='\0';
    	LOGD( "CallState serial receive data state = %s  \n",state);

    	int namelen = sizeof( startZone ) - 1;
    	char name [ namelen ];
    	memset(name, 0, namelen );
    	memcpy(name, startZone + 1, namelen );
//
    	LOGD( "CallState serial receive data name = %s  \n",name);
    	LOGD( "CallState serial receive data number = %s  \n",endZone);

        //Android Send: HFP_OUTGOING = 2;HFP_INCOMING = 3;HFP_HANG_UP = 4;HFP_CONNECTING = 5;
    	bool hangup = false;
    	int app_status = atoi(state);
    	int status = atoi(state);
    	//0 Disconnected,1 Sending, 2 Ringing
    	//3 Connecting,4 Active,5 Held,6 Disconnecting
    	int direction = 0;//0 Unknown,1 Incoming,2 Outgoing
    	if(callStateInfo != nullptr )
    	{
    		direction = callStateInfo->direction;
    	}
    	if( app_status == APP_HFP_INCOMING)
    	{
    		//HFP_INCOMING
    		direction = 1;
    		status = 2;//2 Ringing
    	}
    	else if( app_status == APP_HFP_OUTGOING)
    	{
    		//HFP_OUTGOING
    		direction = 2;
    		status = 1;// 1 Sending
    	}
    	else if( app_status == APP_HFP_HANG_UP)
    	{
    		//HFP_HANG_UP
    		hangup = true;
    		status = 0; //Disconnected
    	}
    	else if( app_status == APP_HFP_CONNECTING)
    	{
    		//HFP_CONNECTING
    		status = 4;//4 Active
    	}

    	if ( callStateInfo == NULL )
    	{
    		//直接更新状态
    		callStateInfo =(struct CallStateInfo *) malloc(sizeof( struct CallStateInfo ));
    	}else {
    		if( status == callStateInfo->status )
    		{
    			LOGD( "CallState serial receive the same CallState ignore. \n");
    			return;
    		}
    		if(direction == 0 && status != 0)
    		{
    			direction = callStateInfo->direction;
    		}
    	}

    	memset(callStateInfo->remoteId ,0, 1024);
    	memcpy(callStateInfo->remoteId ,endZone, sizeof(endZone));
    	memset(callStateInfo->displayName ,0, 1024);
    	memcpy(callStateInfo->displayName ,name, sizeof(name));
    	if( app_status == APP_HFP_CONNECTING)
    	{
    		//HFP_CONNECTING
//    		if(direction == 1/**Incoming**/)
//    		{
//    			callStateInfo->status = 3;/** 3 Connecting**/
//    			callStateInfo->direction = direction;
//    			sendCallStateUpdateInfo(callStateInfo);
//    		}
    	}
    	else if( app_status == APP_HFP_HANG_UP)
    	{
    		//APP_HFP_HANG_UP
    		if(direction == 1/**Incoming**/)
    		{
    			callStateInfo->status = 6;/** 6 Disconnecting **/
    			callStateInfo->direction = direction;
    			sendCallStateUpdateInfo(callStateInfo);
    			usleep( 20 * 1000);
    		}
    	}

    	callStateInfo->status = status;
    	callStateInfo->direction = direction;
    	sendCallStateUpdateInfo(callStateInfo);

    	if( hangup == true)
    	{
    		//HFP_HANG_UP = 4;
    		if(callStateInfo != NULL)
    		{
    			free(callStateInfo);
    			callStateInfo = NULL;
    		}
    	}
    }
}

void OnHidGadgetReadyRequest(int hidReady ){
	//LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "%s:%d\n", __func__, hidReady);
	if( hidReady == 1 ){
		hidGadgetFunc = 1;
		LOGD( "OnHidGadgetReadyRequest ");
		__system_property_set("sys.shark.carplay.hidg", "1");
		HidGadgetInit();
	}

}

void OnKernelConnected(int connected ){
	//LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "%s:%d\n", __func__, connected);
	if( connected == 1 ){

#if 1
	// switch to devices
//	usleep(1500*1000);//wait 1500ms for config apple device
	if (check_usb_usb_gadget_UDC() == 1) {
		LOGD( "OnKernelConnected -> Do switch to device\n");
		UsbSwitcher_Device();
	}
	else{
		UsbSwitcher_Host();
	}
#endif
	}

}
/**检测到支持CarPlay设备插入**/
void OnCarPlayDevicePlugin( ){
	LOGD( "OnCarPlayDevicePlugin  net_card = %d",net_card);
	__system_property_set("sys.shark.carplay.hidg", "0");
	int initResult = AccessoryLib::getInstance()->accessoryLibInit();
	LOGD( "OnCarPlayDevicePlugin accessoryLibInit initResult: %d",initResult);
	if(initResult >= 0)
	{
		SharkCarPlayInit();
	}
}
void OnRoleSwitchRequest(int role ){
	//LOGD( "%s:%d\n", __func__, __LINE__);
	LOGD( "%s:%d\n", __func__, role);
	if( role == 1 ){
		LOGD( "switch usb mode to host ");
		__system_property_get("ro.board.platform", board_platform);
		if(hidGadgetFunc == 1)
		{
			hidGadgetFunc = 0;
//			HidGadgetUninit();
		}
		int role_ms = 0;
		__system_property_get("persist.usb.role.switch.delay", role_delay);
		if(strlen( role_delay ) > 0 )
		{
			role_ms = atoi(role_delay);
		}
		if( role_ms > 0 )
		{
			usleep( role_ms * 1000 );
		}
		UsbSwitcher_Host();
		net_card = 0;
		AccessoryLib::getInstance()->accessoryLibCreate(OnCarPlayDevicePlugin);
	}

}

int net_detect()
{
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	struct ifreq ifr;
	strcpy(ifr.ifr_name, "usb0");
	if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0 ) {
		LOGD( "net_detect NOREADY\n");
		if(fd >= 0 )close( fd );
		return -1;
	}
	if(ifr.ifr_flags & IFF_RUNNING) {
		LOGD( "net_detect UP\n");
		if(fd >= 0 )close( fd );
		return 1;
	} else {
		LOGD( "net_detect READY\n");
		if(fd >= 0 )close( fd );
		return 0;
	}
}
void OnBluetoothRfcomm(int wlcarplay){
	LOGD( "OnBluetoothRfcomm \n");
	wl_carplay = 1;
	SharkCarPlayInit();
}
void OnCdcNcmStatus(int role){
	LOGD( "%s:%d\n", __func__, role);
	if( role == 1)
	{
		if(sessionConnected == 0)
		{
			net_card = 1;
//			int elapsed_ms = 0;
//			while( net_detect() < 0){
//				usleep(50*1000); //50ms
//				elapsed_ms += 50;
//				if(elapsed_ms >= 1000)
//				{
//					break;
//				}
//				LOGD( "net_detect NOT_READY wait.\n");
//			}
//			usleep(300*1000);
//			system("echo 1 > /proc/sys/net/ipv6/conf/rmnet_data0/disable_ipv6");
//			LOGD( "ifconfig usb0 up ");
//			system("ifconfig usb0 up");
//		   int elapsed_ms_up = 0;
//			while( net_detect() < 1){
//				usleep(50*1000);
//				elapsed_ms_up += 50;
//				if(elapsed_ms_up >= 3000)
//				{
//					break;
//				}
//				LOGD( "net_detect NOT_UP wait.\n");
//			}
			__system_property_set("sys.shark.carplay.hidg", "0");
			__system_property_set("sys.lynx.usb.ncm", "1");
			StartCarPlayNCM();
		}
	}else{
		__system_property_set("sys.lynx.usb.ncm", "0");
      //usb0网卡断开连接了，则需要tear down整个session
		if(sessionConnected == 1)
		{
			DestroyAppleCarPlay();
		}
		UsbSwitcher_Device();
	}
}

void SharkCarPlayInit(){
	LOGD( "SharkCarPlayInit \n");
	CarPlayAppStubDelegateInit( &c2iDelegate );
	c2iDelegate.requestAccessoryRead_f	= _OnRequestAccessoryRead;
	c2iDelegate.requestAccessoryWrite_f = _OnRequestAccessoryWrite;
	c2iDelegate.requestScreenRecordStart_f = _OnRequestScreenRecordStart;
	c2iDelegate.requestScreenRecordStop_f = _OnRequestScreenRecordStop;
	c2iDelegate.requestAudioRecordStart_f = _OnRequestAudioRecordStart;
	c2iDelegate.requestAudioRecordStop_f = _OnRequestAudioRecordStop;
	c2iDelegate.airPlaySessionStarted_f = _OnAirPlaySessionStarted;
	c2iDelegate.airPlaySessionStoped_f = _OnAirPlaySessionStoped;
	c2iDelegate.airPlayScreenTouchEvent_f = _OnAirPlayScreenTouchEvent;
	c2iDelegate.airPlayScreenMultiTouchEvent_f = _OnAirPlayScreenMultiTouchEvent;
	c2iDelegate.airPlayScreenKnobEvent_f = _OnAirPlayScreenKnobEvent;
	c2iDelegate.airPlayScreenMediaButtonEvent_f = _OnAirPlayScreenMediaButtonsEvent;
	c2iDelegate.airPlayScreenDisplay_f = _OnAirPlayScreenDisplay;
	c2iDelegate.airPlayAudioFormatInfo_f = _OnAirPlayAudioFormatInfo;
	c2iDelegate.airPlayModesChanged_f = _OnAirPlayModesChanged;
	c2iDelegate.airPlayInfoChanged_f = _OnAirPlayInfoChanged;
	c2iDelegate.airPlaySetNightMode_f = _OnAirPlaySetNightMode;
	c2iDelegate.airPlayAudioFocusChanged_f = _OnAirPlayAudioFocusChanged;
	c2iDelegate.airPlayRequestNetworkCard_f = _OnAirPlayRequestNetworkCard;
	c2iDelegate.airPlayLocationInfoChanged_f = _OnAirPlayLocationInfoChanged;
	c2iDelegate.airPlayWifiConfigurationInformation_f = _OnAirPlayWifiConfigurationInformation;
	c2iDelegate.requestLibusbOperate_f = _OnRequestLibusbOperate;
	c2iDelegate.requestMicrophoneStart_f = _OnRequestMicrophoneStart;
	c2iDelegate.requestMicrophoneStop_f = _OnRequestMicrophoneStop;
	c2iDelegate.requestAccessoryUsbVidPid_f	= _OnRequestAccessoryUsbVidPid;
	c2iDelegate.requestDisableBluetooth_f	= _OnRequestDisableBluetooth;

	CarPlayAppStubSetDelegate( &c2iDelegate );
	setAudioRecordCallBack(_AudioRecordPcmCallBack);
	setMircophoneCallBack(_MicrophoneRecordPcmCallBack);
	setCallBack(_ScreenRecordVideoCallBack);
	StartAppleCarPlay(0,NULL);
}

int check_usb_usb_gadget_UDC() {
	char value[256];
	int fd;
	memset(g_usb_udc_path, 0, 1024);
	if ((fd = open("/config/usb_gadget/g1/UDC", O_RDONLY)) < 0) {
		LOGE("open(/config/usb_gadget/g1/UDC) failed: %s (%d)\n", strerror(errno), errno);
		return 0;
	}

	memset(g_usb_udc_path, 0, sizeof(g_usb_udc_path));
	read(fd, &g_usb_udc_path, sizeof(g_usb_udc_path));
	char *p = strchr(g_usb_udc_path, '\n');
	if (p != NULL) {
		*p = '\0';
	}
	if (strlen(g_usb_udc_path) > 1) {
       LOGD("/config/usb_gadget/g1/UDC:g_usb_udc_path:%s,len=%d\n", g_usb_udc_path, strlen(g_usb_udc_path)); 
	} else {
		if (strlen(g_usb_udc_path) <= 1) {
			__system_property_get("sys.usb.controller", g_usb_udc_path);
			LOGD("sys.usb.controller:g_usb_udc_path:%s,len=%d\n", g_usb_udc_path, strlen(g_usb_udc_path));
		}
	}
	close(fd);
	return 1;
}
unsigned char ctoi(char c) {
	if ((c >= 'A') && ((c <= 'F')))
		return (c - 'A' + 0x0A);
	if ((c >= 'a') && ((c <= 'f')))
		return (c - 'a' + 0x0A);
	if ((c >= '0') && ((c <= '9')))
		return (c - '0' + 0x00);
	return 0;
}

void usb_driver_handle()
{
	int fd = -1;
	int i = 0;
	fd = open(OEM_PATH, O_RDWR);
	if (fd < 0) {
		printf("open zj_usb_accessory failed\n");
		return;
	}
	for (i = 0; i < string_black_vid_pid_num; i++) {
		if(!ioctl(fd, ZJ_SET_STRING_READ_MODE, &string_black_vid_pid[i])) {
			printf("set value successfully...\n");
		}
	}

	for (i = 0; i < delay_black_vid_pid_num; i++) {
		if(!ioctl(fd, ZJ_SET_CONTROL_DELAY_MODE, &delay_black_vid_pid[i])) {
			printf("set value successfully...\n");
		}
	}
	close(fd);
}

void _HttpCallBack(void* data,int len){
	if( data )
	{
		if( software_activated == 0 && software_activated != ((char*)data)[1])
		{
			software_activated = ((char*)data)[1];
			if( software_activated && sessionConnected )
			{
				start_observe_audio_channel(_OnAudioChannelChanged);
			}
		}

		LOGD( "%s:%d software_activated = %d \n", __func__, __LINE__,software_activated);
		if( software_activated )
		{
			write_serial("IU1\r\n"); //产品已激活
		}else{
			write_serial("IU0\r\n");//产品未激活
		}
	}
}

int EagleLib_init(){
	LOGD( "%s:%d \n", __func__, __LINE__);
	if( versionInfo !=NULL )
	{
		free( versionInfo );
	}
	versionInfo = (char *)malloc(200);
	version_info(versionInfo, 200);
	LOGD( "%s versionInfo = %s  \n", __func__,versionInfo);
	__system_property_set("zj.zsender.version", versionInfo);

	char udisk[92] = { 0 };
	char h264_path [ 200 ] = { 0 };
	__system_property_get("sys.mount.stableName", udisk);
	//  /mnt/media_rw/83F2-60BC/
	LOGD("VideoEncoder read udisk name %s \n",udisk);
	if( strlen( udisk ) > 0 )
	{
		sprintf( h264_path, "/mnt/media_rw/%s%s",udisk, "/simulate.h264" );
		LOGD("VideoEncoder read h264_path  %s \n",h264_path);
		if (access(h264_path, F_OK) == 0)
		{
			simulate_video = 1;
			LOGD("VideoEncoder read simulate_video  %d \n",simulate_video);
		}

	}

	char soft_encoder[92] = { 0 };
	__system_property_get("persist.sys.softsr", soft_encoder);
	if(strlen( soft_encoder ) > 0 )
	{
		soft_video_encoder =  atoi(soft_encoder);
		LOGD("VideoEncoder read soft_video_encoder  %d \n",soft_video_encoder);
	}



	usb_driver_handle();

#if 0
	char calibrationTag [ 10 ];
	__system_property_get("persist.sys.resolution.calibration", calibrationTag);
	if( strlen(calibrationTag) > 0 )
	{
		int tag = atoi( calibrationTag );
		if( tag == 1 )
		{
			__system_property_set("persist.sys.resolution.calibration", "0");
			LOGD( "%s calibration reboot again. \n", __func__);
			system("reboot");
		}
	}
#endif

	deviceId = (char *)malloc(40);
	usbSerialNumber = (char *)malloc(40);
	usbUUID = (char *)malloc(40);
	memset(deviceId,0,40);
	memset(usbSerialNumber,0,40);
	memset(usbUUID,0,40);
	memset(board_serial,0,40);
	__system_property_get("ro.serialno", board_serial);
	if(strlen( board_serial ) > 0)
	{
		//ec be 8f 37
		//BE:20:54:76:02:BF
		char bd_addr[6];
		for (int i = 0; i < 4; i++) {
			bd_addr[i] = ctoi(board_serial[i * 2]) * 16
					+ ctoi(board_serial[i * 2 + 1]);
		}
		bd_addr[4] = 0x02;
		bd_addr[5] = 0xBF;

		LOGD( " bd_addr = %02X %02X %02X %02X %02X %02X \n", bd_addr[0],
				bd_addr[1],bd_addr[2],bd_addr[3],bd_addr[4],bd_addr[5]);

		sprintf( deviceId,"%02X:%02X:%02X:%02X:%02X:%02X", bd_addr[0],
				bd_addr[1],bd_addr[2],bd_addr[3],bd_addr[4],bd_addr[5]);

//		sprintf( usbSerialNumber, "8001004752434d46428b%02x%02x%02x%02x2900", bd_addr[0],
//				bd_addr[1],bd_addr[2],bd_addr[3]);
		sprintf( usbSerialNumber, "8001004752434d46428b%s2900",board_serial);

		sprintf( usbUUID, "A798120D-E7E8-4CE2-9BC5-2B1A%02X%02X%02X%02X", bd_addr[0],
				bd_addr[1],bd_addr[2],bd_addr[3]);

		LOGD( "SharkLib_init deviceId --> %s  \n" , deviceId);
		LOGD( "SharkLib_init usbSerialNumber --> %s  \n" , usbSerialNumber);
		LOGD( "SharkLib_init usbUUID --> %s  \n" , usbUUID);

		__system_property_set("sys.xq.product.deviceid",  deviceId);
//		__system_property_set("sys.xq.product.usbserialno",  usbSerialNumber);
		__system_property_set("sys.xq.product.uuid",  usbUUID);


#if 0
		char mdnsd[256];
		FILE *fp_mdnsd = fopen("/dev/socket/mdnsd-shark.pid", "r");
		if (fp_mdnsd != NULL)
		{
			while (fgets(mdnsd,sizeof(mdnsd),fp_mdnsd))
			{
				mdnsd[255]='\0';		// just to be safe
				LOGD( "SharkLib_init mdnsd pid --> %s  \n" , mdnsd);
				int mdnsd_pid =atoi(mdnsd);
				kill(mdnsd_pid, SIGINT);
				sleep(1);
				system("/system/bin/mdnsd-shark &");
			}
			int fpmdnsd_closed = fclose(fp_mdnsd);
		}
#endif

		char line[256];
		FILE *fp = fopen("/proc/sys/kernel/random/uuid", "r");
		if (fp == NULL) return -1;
		while (fgets(line,sizeof(line),fp))
		{
			line[255]='\0';		// just to be safe
			LOGD( "SharkLib_init usbUUID line --> %s  \n" , line);
		}
		int fp_closed = fclose(fp);
		__system_property_set("sys.xq.product.uuid",  line);
	}

#if 0
	//config apple device
	__system_property_set("sys.usb.config",  "appleSvc");
	__system_property_set("sys.usb.configfs",  "2");
	// switch to devices
	usleep(1500*1000);//wait 1500ms for config apple device
	if (check_usb_usb_gadget_UDC() == 1) {
		LOGD( "Do switch to device\n");
		UsbSwitcher_Device();
	} else {
		__system_property_set("sys.usb.config",  "");
	    __system_property_set("sys.usb.configfs",  "");
		sleep(2);
		__system_property_set("sys.usb.config",  "appleSvc");
	    __system_property_set("sys.usb.configfs",  "2");
	    UsbSwitcher_Device();
	}
#endif
	init_serial(shark_at_command_process);
	observe_role_switch_request(OnRoleSwitchRequest, OnHidGadgetReadyRequest, OnKernelConnected);
	observe_cdc_ncm_status(OnCdcNcmStatus);

	//无线CarPlay反向
//	observe_bluetooth_rfcomm(OnBluetoothRfcomm);

#if 0
	CarPlayAppStubDelegateInit( &c2iDelegate );
	c2iDelegate.requestAccessoryRead_f	= _OnRequestAccessoryRead;
	c2iDelegate.requestAccessoryWrite_f = _OnRequestAccessoryWrite;

	CarPlayAppStubSetDelegate( &c2iDelegate );

	StartAppleCarPlay(0,NULL);
#endif
//	start_http_request(_HttpCallBack);
	return 0;
}

int EagleLib_exit(){
	LOGD( "%s:%d\n", __func__, __LINE__);
	return 0;
}


